using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

using SHFST.Config;
using SHFST.Core;
using SHFST.Agents;
using SHFST.UI;

namespace SHFST.Core
{
   public class SHFST : Microsoft.Xna.Framework.Game
   {
      private enum State
      {
         MENU,
         PLAY,
         PAUSE,
         WIN,
         LOSE
      }

      GraphicsDeviceManager graphics;
      LevelImporter levelImporter;
      SpriteBatch spriteBatch;

      State state;
      bool escDown;
      bool upDown;
      bool downDown;
      bool enterDown;

      int levelSize;
      int levelProgress;
      ScrollingBackground background;
      Salmon salmon;
      List<Enemy> enemies;
      List<InfoBox> infoBoxes;

      Menu mainMenu;
      Menu pauseMenu;
      TextDisplay gameOverDisplay;
      TextDisplay lifeDisplay;
      TextDisplay ammoDisplay;
      TextDisplay scoreDisplay;

      SoundEffectInstance gameMusic;
      SoundEffectInstance lvlStartSound;
      SoundEffectInstance winSound;
      SoundEffectInstance loseSound;

      public SHFST ()
      {
         graphics = new GraphicsDeviceManager (this);
         Content.RootDirectory = "Content";

         escDown = false;
         enterDown = false;
      }

      protected override void Initialize ()
      {
         spriteBatch = new SpriteBatch (GraphicsDevice);
         levelImporter = new LevelImporter ();

         base.Initialize ();

         graphics.PreferredBackBufferWidth = 800;
         graphics.PreferredBackBufferHeight = 600;
         //graphics.IsFullScreen = true;
         graphics.ApplyChanges ();

         SetState (State.MENU);
      }

      protected override void LoadContent ()
      {
         background = new ScrollingBackground ();
         salmon = new Salmon ();
         enemies = new List<Enemy> ();
         infoBoxes = new List<InfoBox> ();

         mainMenu = new Menu ();
         pauseMenu = new Menu ();
         gameOverDisplay = new TextDisplay ();
         lifeDisplay = new TextDisplay ();
         ammoDisplay = new TextDisplay ();
         scoreDisplay = new TextDisplay ();

         levelImporter.read (".\\Content\\Config\\Level1.txt",
                             Content,
                             GraphicsDevice,
                             ref levelSize,
                             ref background,
                             ref salmon,
                             ref enemies,
                             ref infoBoxes);

         Point screenCenter = new Point (GraphicsDevice.Viewport.Width / 2, GraphicsDevice.Viewport.Height / 2);
         SpriteFont titleFont = Content.Load<SpriteFont> (".\\Fonts\\Title");
         SpriteFont hudFont = Content.Load<SpriteFont> (".\\Fonts\\HUD");
         mainMenu.Load ("Super Happy Fun Salmon Time",
                        titleFont,
                        hudFont,
                        screenCenter,
                        Color.White,
                        Color.Red);
         mainMenu.addOption ("Start");
         mainMenu.addOption ("Quit");
         pauseMenu.Load ("Pause",
                         titleFont,
                         hudFont,
                         screenCenter,
                         Color.White,
                         Color.Red);
         pauseMenu.addOption ("Resume");
         pauseMenu.addOption ("Main Menu");
         pauseMenu.addOption ("Quit");
         gameOverDisplay.Load (titleFont, screenCenter);
         gameOverDisplay.color = Color.White;
         lifeDisplay.Load (hudFont, new Point (100, 20));
         ammoDisplay.Load (hudFont, new Point (100, 50));
         scoreDisplay.Load (hudFont, new Point (100, 80));

         gameMusic = Content.Load<SoundEffect> (".\\Sounds\\Core\\Music").CreateInstance ();
         gameMusic.Volume = .75f;
         gameMusic.IsLooped = true;

         lvlStartSound = Content.Load<SoundEffect> (".\\Sounds\\Core\\LevelStart").CreateInstance ();
         winSound = Content.Load<SoundEffect> (".\\Sounds\\Core\\Win").CreateInstance ();
         loseSound = Content.Load<SoundEffect> (".\\Sounds\\Core\\Lose").CreateInstance ();
      }

      protected override void Update (GameTime gameTime)
      {
         KeyboardState kbState = Keyboard.GetState ();

         bool changeState = false;
         bool nowEscDown = kbState.IsKeyDown (Keys.Escape);
         if (!escDown && nowEscDown)
         {
            changeState = true;
         }
         escDown = nowEscDown;

         switch (state)
         {
            case State.MENU:
            {
               if (changeState)
               {
                  Exit ();
               }

               bool moveUp = false;
               bool moveDown = false;
               bool enter = false;
               CheckMenuKeys (kbState, ref moveUp, ref moveDown, ref enter);

               if (moveUp)
               {
                  mainMenu.select (-1);
               }
               else if (moveDown)
               {
                  mainMenu.select (1);
               }
               else if (enter)
               {
                  switch (mainMenu.selectedOption)
                  {
                     case 0:
                     {
                        SetState (State.PLAY);
                     }
                     break;
                     case 1:
                     {
                        Exit ();
                     }
                     break;
                  }
               }
            }
            break;
            case State.PLAY:
            {
               if (changeState)
               {
                  SetState (State.PAUSE);
               }

               lifeDisplay.text = "LIFE: " + salmon.life.ToString ();
               ammoDisplay.text = "EGGS: " + salmon.ammo.ToString ();
               scoreDisplay.text = "SCORE: " + salmon.score.ToString ();

               int speed = 0;
               int time = (int)gameTime.ElapsedGameTime.TotalMilliseconds;
               if (!salmon.Update (ref speed, time))
               {
                  SetState (State.LOSE);
                  break;
               }
               background.Update (speed);

               for (int enemy = 0; enemy < enemies.Count; ++enemy)
               {
                  if (!enemies[enemy].Update (GraphicsDevice, salmon, levelProgress, speed, time))
                  {
                     enemies.RemoveAt (enemy);
                     --enemy;
                  }
               }

               for (int box = 0; box < infoBoxes.Count; ++box)
               {
                  if (!infoBoxes[box].Update (GraphicsDevice, levelProgress, speed))
                  {
                     infoBoxes.RemoveAt (box);
                     --box;
                  }
               }

               levelProgress -= speed;
               if (levelProgress >= levelSize)
               {
                  SetState (State.WIN);
               }
            }
            break;
            case State.PAUSE:
            {
               if (changeState)
               {
                  SetState (State.PLAY);
               }

               bool moveUp = false;
               bool moveDown = false;
               bool enter = false;
               CheckMenuKeys (kbState, ref moveUp, ref moveDown, ref enter);

               if (moveUp)
               {
                  pauseMenu.select (-1);
               }
               else if (moveDown)
               {
                  pauseMenu.select (1);
               }
               else if (enter)
               {
                  switch (pauseMenu.selectedOption)
                  {
                     case 0:
                     {
                        SetState (State.PLAY);
                     }
                     break;
                     case 1:
                     {
                        SetState (State.MENU);
                     }
                     break;
                     case 2:
                     {
                        Exit ();
                     }
                     break;
                  }
               }
            }
            break;
            case State.WIN:
            case State.LOSE:
            {
               if (changeState)
               {
                  SetState (State.MENU);
               }
            }
            break;
         }

         base.Update (gameTime);
      }

      private void CheckMenuKeys (KeyboardState kbState, ref bool moveUp, ref bool moveDown, ref bool enter)
      {
         bool nowUpDown = kbState.IsKeyDown (Keys.Up);
         bool nowDownDown = kbState.IsKeyDown (Keys.Down);
         bool nowEnterDown = kbState.IsKeyDown (Keys.Enter);

         if (!upDown && nowUpDown)
         {
            moveUp = true;
         }
         if (!downDown && nowDownDown)
         {
            moveDown = true;
         }
         if (!enterDown && nowEnterDown)
         {
            enter = true;
         }

         upDown = nowUpDown;
         downDown = nowDownDown;
         enterDown = nowEnterDown;
      }

      protected override void Draw (GameTime gameTime)
      {
         GraphicsDevice.Clear (Color.CornflowerBlue);

         spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend);

         background.Draw (spriteBatch);
         salmon.Draw (spriteBatch);
         foreach (Enemy enemy in enemies)
         {
            if (enemy.active)
            {
               enemy.Draw (spriteBatch);
            }
         }
         foreach (InfoBox box in infoBoxes)
         {
            if (box.active)
            {
               box.Draw (spriteBatch);
            }
         }

         switch (state)
         {
            case State.MENU:
            {
               mainMenu.Draw (spriteBatch);
            }
            break;
            case State.PLAY:
            {
               lifeDisplay.Draw (spriteBatch);
               ammoDisplay.Draw (spriteBatch);
               scoreDisplay.Draw (spriteBatch);
            }
            break;
            case State.PAUSE:
            {
               pauseMenu.Draw (spriteBatch);
            }
            break;
            case State.WIN:
            case State.LOSE:
            {
               gameOverDisplay.Draw (spriteBatch);
            }
            break;
         }

         spriteBatch.End ();

         base.Draw (gameTime);
      }

      private void SetState (State newState)
      {
         switch (newState)
         {
            case State.MENU:
            {
               levelSize = 0;
               levelProgress = 0;
               LoadContent ();

               mainMenu.selectedOption = 0;
               mainMenu.select (0);

               gameMusic.Stop ();
            }
            break;
            case State.PLAY:
            {
               gameMusic.Play ();
               if (state == State.MENU)
               {
                  lvlStartSound.Play ();
               }
            }
            break;
            case State.PAUSE:
            {
               pauseMenu.selectedOption = 0;
               pauseMenu.select (0);

               gameMusic.Pause ();
            }
            break;
            case State.WIN:
            {
               gameOverDisplay.text = "         WINNER!!!\n";
               if (salmon.score < 100)
               {
                  gameOverDisplay.text += " ";
                  if (salmon.score < 10)
                  {
                     gameOverDisplay.text += " ";
                  }
               }
               gameOverDisplay.text += "        SCORE: " + salmon.score + "\n\nPress ESC to continue";

               winSound.Play ();
            }
            break;
            case State.LOSE:
            {
               gameOverDisplay.text = "          LOSER!!!\n\nPress ESC to continue";

               loseSound.Play ();
            }
            break;
         }

         upDown = false;
         downDown = false;

         state = newState;
      }
   }
}
